﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using System.Threading;
namespace EC_Socket
{

    public class EC_Client
    {
        /*使用指南：
 * 先连接服务器： ConnectToServer（string Ip地址）；
 * 然后在RecvData（）中会需要调用处理函数，涉及iNum
 * 然后用 得到的iNum 调用发送函数 SendData(string, int（长度）);
 * 最后调用Close();关闭
 */
        public const int SERVER_PORT = 5000;
        public const int SIZE_OF_PACKET = 1024;
        public const byte SIGN_SIZE = 0x01;
        public const byte SIGN_PACKET_NUM = 0x02;
        public const byte SIGN_PACKET_NUM_END = 0x03;
        public static Semaphore SemWait;
        public string strRecvData;
        public bool bHasConnect = false;
        public Thread threadRecv;
        public Socket m_SockConn;
        //public Semaphore m_Semaphore_Size;
        public int ConnectToServer(string strServerIp)
        {
            if(bHasConnect)
            {
                return -1;
            }
            try
            {
                int iPort = SERVER_PORT;
                IPAddress ip = IPAddress.Parse(strServerIp);
                IPEndPoint ipEnd = new IPEndPoint(ip, iPort);
                m_SockConn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socket
                m_SockConn.Connect(ipEnd);
            }
            catch (SocketException)
            {
                MessageBox.Show("socket exception in Client Conn!");
                return -1;
            }
            catch (ObjectDisposedException)
            {
                MessageBox.Show("Socket已关闭！ in Client Conn!");
                return -1;
            }
            catch (ArgumentNullException)
            {
                MessageBox.Show("remoteEP 为 null! in Client Conn!");
                return -1;
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show("InvalidOperationException ! in Client Conn!");
                return -1;
            }
            bHasConnect = true;
            return 0;
        }


        public void RecvData()
        {
            byte[] btRecvData = new byte[SIZE_OF_PACKET];//缓冲区   
            //开始循环收
            //while (true)
           // {
                bool bLosePacket = false; //是否丢包
                byte btLastNum = 0x00;//包序号
                //先收数据总大小
                try
                {
                    m_SockConn.Receive(btRecvData, 5, 0);
                }
                catch (ObjectDisposedException)
                {
                    SemWait.Release();
                    return ;
                }
                catch (SocketException)
                {
                    SemWait.Release();
                    return ;
                }
                if (btRecvData[0] != SIGN_SIZE)
                {
                    MessageBox.Show("客户端接收错误，not SIGN_SIZE!");
                }
                int iSize = BitConverter.ToInt32(btRecvData, 1);
                int iRemainSize = iSize;
                byte[] btData = new byte[iSize];
                //收数据
                while (iRemainSize >= SIZE_OF_PACKET)
                {
                    //
                    try
                    {
                        m_SockConn.Receive(btRecvData, SIZE_OF_PACKET, 0);
                    }
                    catch (ArgumentNullException)
                    {
                        MessageBox.Show("buffer 为 nullNothingnull! In RecvData(EC_Client)");
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        MessageBox.Show("size 超出了 buffer 的大小 In RecvData(EC_Client)");
                    }
                    catch (SocketException)
                    {
                        MessageBox.Show("试图访问套接字时发生错误 In RecvData(EC_Client)");
                    }
                    catch (ObjectDisposedException)
                    {
                        MessageBox.Show("ObjectDisposedException In RecvData(EC_Client)");
                    }
                    if (btRecvData[0] == SIGN_PACKET_NUM)
                    {
                        if (btRecvData[1] == btLastNum)
                        {
                            Array.Copy(btRecvData, 2, btData, iSize - iRemainSize, SIZE_OF_PACKET - 2);
                        }
                        else
                        {
                            //丢包了
                            bLosePacket = true;
                        }
                        btLastNum = (byte)(btLastNum + 1);
                    }
                    iRemainSize -= SIZE_OF_PACKET;
                }
                //最后一块
                try
                {
                    m_SockConn.Receive(btRecvData, iRemainSize + 2, 0);
                }
                catch (ArgumentNullException)
                {
                    MessageBox.Show("buffer 为 nullNothingnull! In RecvData(EC_Client)");
                }
                catch (ArgumentOutOfRangeException)
                {
                    MessageBox.Show("size 超出了 buffer 的大小 In RecvData(EC_Client)");
                }
                catch (SocketException)
                {
                    MessageBox.Show("试图访问套接字时发生错误 In RecvData(EC_Client)");
                }
                catch (ObjectDisposedException)
                {
                    MessageBox.Show("ObjectDisposedException In RecvData(EC_Client)");
                }
                if (btRecvData[0] == SIGN_PACKET_NUM_END)
                {
                    if (btRecvData[1] == 0xff)
                    {
                        Array.Copy(btRecvData, 2, btData, iSize - iRemainSize, iRemainSize);
                    }
                    else
                    {
                        //丢包了
                        bLosePacket = true;
                    }
                }
                if (bLosePacket)
                {
                    //丢包了
                    MessageBox.Show("丢包了");
                }
                else
                {
                    //没丢包
                    strRecvData = Encoding.UTF8.GetString(btData, 0, iSize);
                    //信号量。
                    SemWait.Release();
                    return;
                    //MessageBox.Show(str);

                }
                SemWait.Release();
          //  }
        }




        public string SendData(string strData, int iSize)
        {
            try
            {
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strData);
                byte[] btSizePack = new byte[1024];
                //先发长度
                btSizePack[0] = SIGN_SIZE;
                byte[] btSize = BitConverter.GetBytes(iSize);
                Array.Copy(btSize, 0, btSizePack, 1, btSize.Length);
                m_SockConn.Send(btSizePack, 5, 0);
                int iRemainSize = iSize;
                byte btPackNum = 0x00;
                byte[] btSendPack = new byte[1024];
                while (iRemainSize >= SIZE_OF_PACKET - 2)
                {
                    btSendPack[0] = SIGN_PACKET_NUM;
                    btSendPack[1] = btPackNum;
                    int iSizeSend = iSize - iRemainSize;
                    for (int i = 0; i < SIZE_OF_PACKET - 2; i++)
                    {
                        btSendPack[i + 2] = buffer[iSizeSend + i];
                    }
                    m_SockConn.Send(btSendPack, SIZE_OF_PACKET, 0);
                    iRemainSize -= SIZE_OF_PACKET;
                    btPackNum = (byte)(btPackNum + 1);
                }
                //最后一块
                btSendPack[0] = SIGN_PACKET_NUM_END;
                btSendPack[1] = 0xff;
                Array.Copy(buffer, iSize - iRemainSize, btSendPack, 2, iRemainSize);
                m_SockConn.Send(btSendPack, iRemainSize + 2, 0);
            }
            catch (ArgumentNullException)
            {
                MessageBox.Show("buffer 为 null! In SendData(EC_Client)");
            }
            catch (ArgumentOutOfRangeException)
            {
                MessageBox.Show(" size 小于 0 或超过缓冲区的大小。In SendData(EC_Client)");
            }
            catch (SocketException)
            {
                MessageBox.Show("socketFlags 不是值的有效组合。In SendData(EC_Client)");
            }
            catch (ObjectDisposedException)
            {
                MessageBox.Show("ObjectDisposedException In SendData(EC_Client)");
            }
            //发完了
            //等待接收
            //创建一个线程？ 接收数据。
            SemWait = new Semaphore(0, 1);
            threadRecv = new Thread(new ThreadStart(RecvData));
            threadRecv.Name = "RecvThread";
            threadRecv.Start();            
            SemWait.WaitOne();
            MessageBox.Show(strRecvData);
            return strRecvData;

        }
        public void Close()
        {
            //threadRecv.Abort();
            m_SockConn.Close();
        }
    }
}
